
#include "rtthread.h"
#include "rthw.h"
#include "stm32f10x.h"
#include "led_key.h"
#include "board.h"

#define LED_R_Pin           GPIO_Pin_1
#define LED_R_GPIO_Port     GPIOA
#define LED_G_Pin           GPIO_Pin_2
#define LED_G_GPIO_Port     GPIOA
#define LED_B_Pin           GPIO_Pin_3
#define LED_B_GPIO_Port     GPIOA

void hw_led_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /*Configure GPIO pin : LED_R/LED_G/LED_B Pin */
    GPIO_SetBits(GPIOA, LED_R_Pin | LED_G_Pin | LED_B_Pin);
    GPIO_InitStruct.GPIO_Pin = LED_R_Pin | LED_G_Pin | LED_B_Pin;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void hw_led_set(uint32_t leds, led_op_t op)
{
    uint16_t pins = 0;
    if (leds & BOARD_LED_RED)
    {
        pins |= LED_R_Pin;
    }
    if (leds & BOARD_LED_GREEN)
    {
        pins |= LED_G_Pin;
    }
    if (leds & BOARD_LED_BLUE)
    {
        pins |= LED_B_Pin;
    }

    if (op == LED_OP_ON)
    {
        GPIO_ResetBits(GPIOA, pins);
    }
    else if (op == LED_OP_OFF)
    {
        GPIO_SetBits(GPIOA, pins);
    }
    else
    {
        uint16_t pin_val = GPIO_ReadOutputData(GPIOA)
                            & (LED_R_Pin | LED_G_Pin | LED_B_Pin);
        uint16_t set_val = pin_val ^ pins;
        uint16_t set_pins = set_val & pins;
        uint16_t reset_pins = (~set_val) & pins;
        if(set_pins)
        {
            GPIO_SetBits(GPIOA, set_pins);
        }
        if (reset_pins)
        {
            GPIO_ResetBits(GPIOA, reset_pins);
        }
    }
}


#define KEY2_Pin            GPIO_Pin_13
#define KEY2_GPIO_Port      GPIOC
#define KEY1_Pin            GPIO_Pin_0
#define KEY1_GPIO_Port      GPIOA
#define KEY_JITTER_TIME     50  //systick counts

static volatile rt_uint32_t key_cur, key_old, key_keep_time, key_en,
                         key_press, key_up, key_down, key_last;

static struct rt_semaphore key_sem;

static rt_uint32_t get_board_key_val(void)
{
    rt_uint32_t key_value = 0;

    if((KEY1_GPIO_Port->IDR & KEY1_Pin))
    {
        key_value |= 0x01;
    }
    if((KEY2_GPIO_Port->IDR & KEY2_Pin))
    {
        key_value |= 0x02;
    }

    return key_value;
}

static void rt_key_periodic(void *para)
{
    rt_base_t level = rt_hw_interrupt_disable();
    if(key_en)
    {
        key_cur = get_board_key_val();
        if(key_cur != key_old)
        {
            key_keep_time = 0;
            key_old = key_cur;
        }
        else
        {
            key_keep_time ++;
            if(key_keep_time == KEY_JITTER_TIME)
            {
                if (key_press != key_old && !key_sem.value)
                {
                    rt_sem_release(&key_sem);
                }
                key_press = key_old;
                key_down |=  ((~key_last) & key_press);
                key_up |= (key_last & (~key_press));
                key_last = key_press;
            }
        }
    }
    rt_hw_interrupt_enable(level);
}

void rt_key_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /*Configure GPIO pin : KEY1_Pin */
    GPIO_InitStruct.GPIO_Pin = KEY1_Pin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

    /*Configure GPIO pin : KEY2_Pin */
    GPIO_InitStruct.GPIO_Pin = KEY2_Pin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);

    key_cur = 0;
    key_old = 0;
    key_keep_time = 0;
    key_press = 0;
    key_up = 0;
    key_down = 0;
    key_last = 0;
    key_en = 0;

    rt_err_t result = rt_register_tick_hook(rt_key_periodic, RT_NULL);
    RT_ASSERT(!result);
    result = rt_sem_init(&key_sem,"key", 0, RT_IPC_FLAG_FIFO);
    RT_ASSERT(!result);
}

static void _key_dis_en(rt_uint32_t enable)
{
    rt_base_t level = rt_hw_interrupt_disable();
    key_cur = 0;
    key_old = 0;
    key_keep_time = 0;
    key_press = 0;
    key_up = 0;
    key_down = 0;
    key_last = 0;
    key_en = enable;
    rt_hw_interrupt_enable(level);
}

rt_err_t rt_key_wait(rt_int32_t tick)
{
    return rt_sem_take(&key_sem, tick);
}

void rt_key_enable(void)
{
    _key_dis_en(1);
}

void rt_key_disable(void)
{
    _key_dis_en(0);
}

rt_uint32_t rt_key_get_press(void)
{
    rt_base_t level = rt_hw_interrupt_disable();
    rt_uint32_t val = key_press;
    rt_hw_interrupt_enable(level);
    return val;
}

rt_uint32_t rt_key_get_down(rt_uint32_t keys)
{
    rt_base_t level = rt_hw_interrupt_disable();
    rt_uint32_t val = key_down & keys;
    key_down &= ~keys;
    rt_hw_interrupt_enable(level);
    return val;
}

rt_uint32_t rt_key_get_up(rt_uint32_t keys)
{
    rt_base_t level = rt_hw_interrupt_disable();
    rt_uint32_t val = key_up & keys;
    key_up &= ~keys;
    rt_hw_interrupt_enable(level);
    return val;
}
